package com.yc.myspringboot.service.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipOutputStream;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Expand;
import org.apache.tools.zip.ZipEntry;

public class CompressUtil {

	/**
	 * 和下面compress方法的区别就是这个方法压缩包外面没有文件夹
	 * @desc 将源文件/文件夹生成指定格式的压缩文件,格式zip
	 * @param resourePath 源文件/文件夹
	 * @param targetPath  目的压缩文件保存路径
	 * @return void
	 * @throws Exception
	 */
	public static void compressedFile(String resourcesPath, String targetPath) throws Exception {
		File resourcesFile = new File(resourcesPath); // 源文件

		FileOutputStream outputStream = new FileOutputStream(targetPath);
		ZipOutputStream out = null;
		try {
			out = new ZipOutputStream(new BufferedOutputStream(outputStream));
			createCompressedFile(out, resourcesFile, "");
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}
	}

	/**
	 * @desc 生成压缩文件。 如果是文件夹，则使用递归，进行文件遍历、压缩 如果是文件，直接压缩
	 * @param out  输出流
	 * @param file 目标文件
	 * @return void
	 * @throws IOException
	 * @throws Exception
	 */
	public static void createCompressedFile(ZipOutputStream out, File file, String dir) throws IOException {
		// 如果当前的是文件夹，则进行进一步处理
		if (file.isDirectory()) {
			// 得到文件列表信息
			File[] files = file.listFiles();
			// 将文件夹添加到下一级打包目录
			out.putNextEntry(new ZipEntry(dir + "/"));

			dir = dir.length() == 0 ? "" : dir + "/";

			// 循环将文件夹中的文件打包
			for (int i = 0; i < files.length; i++) {
				createCompressedFile(out, files[i], dir + files[i].getName()); // 递归处理
			}

		} else { // 当前的是文件，打包处理
			FileInputStream fis = null;
			try {
				// 文件输入流
				fis = new FileInputStream(file);

				out.putNextEntry(new ZipEntry(dir));
				// 进行写操作
				int j = 0;
				byte[] buffer = new byte[1024];
				while ((j = fis.read(buffer)) > 0) {
					out.write(buffer, 0, j);
				}

			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				// 关闭输入流
				if (null != fis) {
					fis.close();
				}
			}

		}
	}

	/**
	 * 解压zip格式压缩包 对应的是ant.jar
	 */
	private static void unzip(String sourceZip, String destDir) throws Exception {
		try {
			Project p = new Project();
			Expand e = new Expand();
			e.setProject(p);
			e.setSrc(new File(sourceZip));
			e.setOverwrite(false);
			e.setDest(new File(destDir));
			/*
			 * ant下的zip工具默认压缩编码为UTF-8编码， 而winRAR软件压缩是用的windows默认的GBK或者GB2312编码 所以解压缩时要制定编码格式
			 */
//			e.setEncoding("gbk");
			e.execute();
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 解压缩
	 */
	public static void deCompress(String sourceFile, String destDir) throws Exception {
		// 保证文件夹路径最后是"/"或者"\"
		char lastChar = destDir.charAt(destDir.length() - 1);
		if (lastChar != '/' && lastChar != '\\') {
			destDir += File.separator;
		}
		// 根据类型，进行相应的解压缩
		String type = sourceFile.substring(sourceFile.lastIndexOf(".") + 1);
		if (type.equals("zip")) {
			CompressUtil.unzip(sourceFile, destDir);
		} else {
			throw new Exception("只支持zip的压缩包！");
		}
	}
	
	
	
	
    /**
     * 和上面compressedFile方法的区别就是这个方法压缩包外面有文件夹
     * @Description: 执行压缩
     * @param srcPathName 被压缩文件
     */
    public static void compress(String srcPathName, String zipFilePath) {
        File file = new File(srcPathName);
        if (!file.exists()) {
            throw new RuntimeException(srcPathName + "不存在！");
        }
        ZipOutputStream out = null;
        try {
            // 创建文件输出流
            FileOutputStream fileOutputStream = new FileOutputStream(new File(zipFilePath));
            CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream, new CRC32());
            out = new ZipOutputStream(cos);
            String basedir = "";
            compress(file, out, basedir);
            out.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
        	if (out != null) {
        		try {
					out.close();
				} catch (IOException e1) {
					throw new RuntimeException(e1);
				}
        	}
        }
    }

    /**
     * @Description: 判断路径是目录还是文件
     * @param file 被压缩文件
     * @param out 容器
     * @param basedir 路径
     */
    private static void compress(File file, ZipOutputStream out, String basedir) {
        /* 判断是目录还是文件 */
        if (file.isDirectory()) {
            System.out.println("压缩：" + basedir + file.getName());
            compressDirectory(file, out, basedir);
        } else {
            System.out.println("压缩：" + basedir + file.getName());
            compressFile(file, out, basedir);
        }
    }

    /**
     * @Description: 压缩一个目录
     * @param dir
     * @param out
     * @param basedir
     */
    private static void compressDirectory(File dir, ZipOutputStream out, String basedir) {
        if (!dir.exists()) {
            return;
        }
        // 获取目录下的所有文件
        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            /* 递归 */
            compress(files[i], out, basedir + dir.getName() + "/");
        }
    }

    /**
     * @Description: 压缩一个文件
     * @param file
     * @param out
     * @param basedir
     */
    private static void compressFile(File file, ZipOutputStream out, String basedir) {
        if (!file.exists()) {
            return;
        }
        BufferedInputStream bis = null;
        try {
            // 将被压缩文件转化为缓冲输入流
            bis = new BufferedInputStream(new FileInputStream(file));
            // 创建压缩包
            ZipEntry entry = new ZipEntry(basedir + file.getName());
            out.putNextEntry(entry);// 压缩文件名称
            int count;
            byte data[] = new byte[1024];
            while ((count = bis.read(data)) != -1) {
                out.write(data, 0, count);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
        	if (bis != null) {
        		try {
					bis.close();
				} catch (IOException e1) {
					throw new RuntimeException(e1);
				}
        	}
        }
    }
	
    /**
     * args[1]解压临时目录tempDir
     * args[2]压缩包路径compressFilePath
     * @param args
     */
    public static void main(String[] args) {
		System.out.println("-----------");
		try {
			CompressUtil.deCompress(args[1], args[0]);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}
